/**
 * Copyright (C), 2002-2017, 上海巧房信息技术有限公司
 * FileName: CollectRuleServiceImpl
 * @Author:   yi.li
 * Date:     2018/6/29 17:17
 * Description: 采集规则服务实现
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.qiaofang.collectmanage.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.qiaofang.collectmanage.analysis.HtmlAnalysisConsts;
import com.qiaofang.collectmanage.analysis.HtmlAnalysisUtils;
import com.qiaofang.collectmanage.analysis.ReturnElement;
import com.qiaofang.collectmanage.base.configuration.CollectManageConfiguration;
import com.qiaofang.collectmanage.constants.CollectRuleFieldEnum;
import com.qiaofang.collectmanage.dao.CollectRuleDao;
import com.qiaofang.collectmanage.dao.ElementRuleDao;
import com.qiaofang.collectmanage.dao.domain.CollectRule;
import com.qiaofang.collectmanage.dao.domain.ElementRule;
import com.qiaofang.collectmanage.dao.util.ElementRuleDaoConvert;
import com.qiaofang.collectmanage.service.CollectRuleService;
import com.qiaofang.collectmanage.service.common.bean.RequestResponseInfo;
import com.qiaofang.collectmanage.service.common.utils.HttpClientUtils;
import com.qiaofang.collectmanage.service.common.utils.phone.RecognitionPhoneNumberUtils;
import com.qiaofang.collectmanage.service.util.CollectRuleServiceConvert;
import com.qiaofang.collectmanage.stub.bean.*;
import com.qiaofang.collectmanage.stub.constants.*;
import com.qiaofang.common.exception.BusinessException;
import com.qiaofang.common.model.page.PageDTO;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class CollectRuleServiceImpl implements CollectRuleService {
	private static final Logger LOGGER = LoggerFactory.getLogger(CollectRuleServiceImpl.class);

	@Autowired
	CollectManageConfiguration collectManageConfiguration;

	@Autowired
	CollectRuleDao collectRuleDao;

	@Autowired
	ElementRuleDao elementRuleDao;

	@Override
	public CollectRuleDTO getCollectRuleById(Integer id){
		CollectRule collectRule = collectRuleDao.getCollectRuleById(id);
		return CollectRuleServiceConvert.convertDomain2DTO(collectRule);
	}

	@Override
	public void saveCollectRule(SaveCollectRuleDTO saveCollectRuleDTO) {
		if(!CollectTypeEnum.valueExist(saveCollectRuleDTO.getCollectType())){
			throw new BusinessException(CollectRuleResponseCode.INVALID_COLLECT_TYPE.getResponseCode(),CollectRuleResponseCode.INVALID_COLLECT_TYPE.getResponseMessage());
		}
		if(!BelongerEnum.valueExist(saveCollectRuleDTO.getBelonger())){
			throw new BusinessException(CollectRuleResponseCode.INVALID_BELONGER.getResponseCode(),CollectRuleResponseCode.INVALID_BELONGER.getResponseMessage());
		}
		if(!CollectHouseTypeEnum.valueExist(saveCollectRuleDTO.getCollectHouseType())){
			throw new BusinessException(CollectRuleResponseCode.INVALID_HOUSE_TYPE.getResponseCode(),CollectRuleResponseCode.INVALID_HOUSE_TYPE.getResponseMessage());
		}

		//查询采集规则是否有过
		CollectRuleDTO getCollectRule = new CollectRuleDTO();
		getCollectRule.setCity(saveCollectRuleDTO.getCity());
		getCollectRule.setSource(saveCollectRuleDTO.getSource());
		getCollectRule.setBelonger(saveCollectRuleDTO.getBelonger());
		getCollectRule.setCollectHouseType(saveCollectRuleDTO.getCollectHouseType());
		getCollectRule.setCollectType(saveCollectRuleDTO.getCollectType());

		List<CollectRuleDTO> collectRuleDTOList =  getListByCollectRule(getCollectRule);
		if (collectRuleDTOList!= null&&collectRuleDTOList.size()>0) {
			CollectRuleDTO collectRuleDTO = collectRuleDTOList.get(0);
			if(DeletedEnum.NO.getValue().equals(collectRuleDTO.getDeleted())) {
				throw new BusinessException(CollectRuleResponseCode.ADD_COLLECTRULE_DUPLICATE.getResponseCode(),
						CollectRuleResponseCode.ADD_COLLECTRULE_DUPLICATE.getResponseMessage());
			}else{
				UpdateCollectRuleDTO updateCollectRuleDTO = CollectRuleServiceConvert.convertSaveDTO2Update(saveCollectRuleDTO);
				updateCollectRuleDTO.setId(collectRuleDTO.getId());
				updateCollectRuleDTO.setUuid(collectRuleDTO.getUuid());
				updateCollectRuleDTO.setDeleted(DeletedEnum.NO.getValue());
				collectRuleDao.updateCollectRule(CollectRuleServiceConvert.convertUpdateDTO2Domain(updateCollectRuleDTO));
				return;
			}
		}
		//添加采集规则
		collectRuleDao.saveCollectRule(CollectRuleServiceConvert.convertSaveDTO2Domain(saveCollectRuleDTO));
	}



	@Override
	public CollectRuleDTO getCollectRule(GetCollectRuleDTO dto) {
		CollectRule domain = collectRuleDao.getCollectRule(CollectRuleServiceConvert.convertGetDTO2Domain(dto));
		return CollectRuleServiceConvert.convertDomain2DTO(domain);
	}

	public List<CollectRuleDTO> getListByCollectRule(CollectRuleDTO collectRuleDTO) {
		return collectRuleDao.getListByCollectRule(CollectRuleServiceConvert.convertDTO2Domain(collectRuleDTO)).stream().map(CollectRuleServiceConvert::convertDomain2DTO).collect(Collectors.toList());
	}

	@Override
	public int updateCollectRule(UpdateCollectRuleDTO updateCollectRuleDTO) {
		if(!CollectTypeEnum.valueExist(updateCollectRuleDTO.getCollectType())){
			throw new BusinessException(CollectRuleResponseCode.INVALID_COLLECT_TYPE.getResponseCode(),CollectRuleResponseCode.INVALID_COLLECT_TYPE.getResponseMessage());
		}
		if(!BelongerEnum.valueExist(updateCollectRuleDTO.getBelonger())){
			throw new BusinessException(CollectRuleResponseCode.INVALID_BELONGER.getResponseCode(),CollectRuleResponseCode.INVALID_BELONGER.getResponseMessage());
		}
		if(!CollectHouseTypeEnum.valueExist(updateCollectRuleDTO.getCollectHouseType())){
			throw new BusinessException(CollectRuleResponseCode.INVALID_HOUSE_TYPE.getResponseCode(),CollectRuleResponseCode.INVALID_HOUSE_TYPE.getResponseMessage());
		}
        return collectRuleDao.updateCollectRule(CollectRuleServiceConvert.convertUpdateDTO2Domain(updateCollectRuleDTO));
	}

	@Override
	public List<CollectRuleDTO> listCollectRule(ListCollectRuleDTO collectRuleDTO) {
		return collectRuleDao.listCollectRule(CollectRuleServiceConvert.convertListDTO2Domain(collectRuleDTO)).stream().map(CollectRuleServiceConvert::convertDomain2DTO).collect(Collectors.toList());
	}

	@Override
	public int removeCollectRule(RemoveCollectRuleDTO removeCollectRuleDTO) {
		if(null==collectRuleDao.getCollectRuleById(removeCollectRuleDTO.getId())){
		   throw new BusinessException(CollectRuleResponseCode.CODE_404.getResponseCode(),CollectRuleResponseCode.CODE_404.getResponseMessage());
		}
		return collectRuleDao.removeCollectRule(removeCollectRuleDTO.getId());
	}

	@Override
	public List<CollectRuleDTO> searchCollectRulePage(SearchCollectRulePostDTO searchCollectRulePostDTO, PageDTO page) {
		if(page==null){
			page = new PageDTO();
		}
		List<CollectRule> list = collectRuleDao.searchCollectRulePage(searchCollectRulePostDTO, page);
		List<CollectRuleDTO> listDTO = new ArrayList<>();
		if(list!=null) {
		      listDTO = list.stream().map(CollectRuleServiceConvert::convertDomain2DTO).collect(Collectors.toList());
		}
		return listDTO;
	}

	@Override
	public Long countSearchCollectRulePage(SearchCollectRulePostDTO dto) {
		return collectRuleDao.countSearchCollectRulePage(dto);
	}


	@Override
	public void commonCityExtend(String city, String source, String belonger, String collectType, String collectHouseType, List<CommonCityExtendDTO> data) {
		if(!CollectTypeEnum.valueExist(collectType)){
			throw new BusinessException(CollectRuleResponseCode.INVALID_COLLECT_TYPE.getResponseCode(),CollectRuleResponseCode.INVALID_COLLECT_TYPE.getResponseMessage());
		}
		if(!BelongerEnum.valueExist(belonger)){
			throw new BusinessException(CollectRuleResponseCode.INVALID_BELONGER.getResponseCode(),CollectRuleResponseCode.INVALID_BELONGER.getResponseMessage());
		}
		if(!CollectHouseTypeEnum.valueExist(collectHouseType)){
			throw new BusinessException(CollectRuleResponseCode.INVALID_HOUSE_TYPE.getResponseCode(),CollectRuleResponseCode.INVALID_HOUSE_TYPE.getResponseMessage());
		}


		GetCollectRuleDTO getCollectRuleDTORequest = new GetCollectRuleDTO();
		getCollectRuleDTORequest.setCity(city);
		getCollectRuleDTORequest.setSource(source);
		getCollectRuleDTORequest.setBelonger(belonger);
		getCollectRuleDTORequest.setCollectType(collectType);
		getCollectRuleDTORequest.setCollectHouseType(collectHouseType);

		CollectRuleDTO  collectRuleDTO = getCollectRule(getCollectRuleDTORequest);
		if(collectRuleDTO==null){
			throw new BusinessException(CollectRuleResponseCode.CODE_404.getResponseCode(),CollectRuleResponseCode.CODE_404.getResponseMessage());
		}
		List<ElementRule> elementRules = elementRuleDao.getElementRuleByUUid(collectRuleDTO.getUuid());

		List<ElementRule> batchElementRules = new ArrayList<ElementRule>();

		List<CollectRule>  collectRuleList = new ArrayList<>();
		if(collectRuleDTO != null){
			data.forEach(commonCityExtendDTO -> {
				collectRuleDTO.setId(null);
				String uuid = UUID.randomUUID().toString();
				collectRuleDTO.setUuid(uuid);
				collectRuleDTO.setCity(commonCityExtendDTO.getCity());
				collectRuleDTO.setWebsite(commonCityExtendDTO.getWebsite());
				collectRuleDTO.setCreatedTime(new Date());
				collectRuleDTO.setUpdatedTime(new Date());
				collectRuleDTO.setDeleted(DeletedEnum.NO.getValue());
				CollectRule collectRule = CollectRuleServiceConvert.convertDTO2Domain(collectRuleDTO);
				collectRuleList.add(collectRule);
				//添加相关
				elementRules.stream().forEach(elementRule -> {

					ElementRule copyElementRule = new ElementRule();
					copyElementRule.setId(null);
					copyElementRule.setCollectRuleUuid(uuid);
					copyElementRule.setDepth(elementRule.getDepth());
					copyElementRule.setDepthDesc(elementRule.getDepthDesc());
					copyElementRule.setFieldName(elementRule.getFieldName());
					copyElementRule.setReturnElement(elementRule.getReturnElement());
					copyElementRule.setReturnElementValue(elementRule.getReturnElementValue());
					copyElementRule.setReturnValue(elementRule.getReturnValue());
					copyElementRule.setCreatedUserId(elementRule.getCreatedUserId());
					copyElementRule.setUpdatedUserId(elementRule.getUpdatedUserId());
					copyElementRule.setCreatedTime(new Date());
					copyElementRule.setUpdatedTime(new Date());
					copyElementRule.setDeleted(DeletedEnum.NO.getValue());
					batchElementRules.add(copyElementRule);
				});
			});
		}
		//批量存collectRule
		collectRuleDao.saveCollectRuleBatch(collectRuleList);
		//批量存elementRule
		elementRuleDao.saveElementRuleBatch(batchElementRules);
	}

	@Override
	public List<String> getCitys() {
		return collectRuleDao.getCitys();
	}

	@Override
	public List<String> getSources() {
		return  collectRuleDao.getSources();
	}
	@Override
	public JSONObject startData(String city, String source, String belonger, String collectType, String collectHouseType, String titleLink) throws Exception{
		CollectRule rule = new CollectRule();
		rule.setCity(city);
		rule.setSource(source);
		rule.setBelonger(belonger);
		rule.setCollectHouseType(collectHouseType);
		rule.setCollectType(collectType);
		CollectRule rsolveCollectRule = collectRuleDao.getCollectRule(rule);
		int index = 1;

        return analyseOneSite(rsolveCollectRule, index, titleLink);
	}



    private JSONObject analyseOneSite(CollectRule rule, int index, String titleLink) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(CollectRuleFieldEnum.CITY.getValue(), rule.getCity());
        jsonObject.put(CollectRuleFieldEnum.SOURCE.getValue(), rule.getSource());
        jsonObject.put(CollectRuleFieldEnum.WEBSITE.getValue(), rule.getWebsite().replace("{}", index + ""));
        jsonObject.put(CollectRuleFieldEnum.COLLECT_TYPE.getValue(), rule.getCollectType());
        jsonObject.put(CollectRuleFieldEnum.COLLECT_HOUSE_TYPE.getValue(), rule.getCollectHouseType());
        jsonObject.put(CollectRuleFieldEnum.BELONGER.getValue(), rule.getBelonger());
        try {
            List<Integer> depths = elementRuleDao.findDepthsByUuid(rule.getUuid());
            if (StringUtils.isBlank(titleLink)) {
                // 获取网站地址对应的html
                String url = jsonObject.getString(CollectRuleFieldEnum.WEBSITE.getValue());

                Document document = Jsoup.parse(HttpClientUtils.getPagetext(url, rule.getListWebCode()).getResponseText());
                //  查看房源列表
                List<ElementRule> ruleList = elementRuleDao.findByUuidAndDepth(rule.getUuid(), depths.get(depths.size() - 3));
                String[] rules = HtmlAnalysisConsts.PARAMETER_SEPARATOR.split(ruleList.get(0).getReturnElement());
                // 查到了房源列表
                Elements list = document.select(rules[1].trim());
                if (list == null || list.isEmpty()) {
                    return jsonObject;
                }
                //最顶上一条
                Element listTopBlock = list.get(0);

                return analyseListTop(listTopBlock, rule, depths, jsonObject);
            } else {
                jsonObject.put(HtmlAnalysisConsts.TITLE_LINK, titleLink);
                return analyseDetail(rule, depths, jsonObject);
            }
        } catch (Exception e) {
            return jsonObject;
        }
    }

	public JSONObject analyseListTop(Element listTopBlock, CollectRule rule, List<Integer> depths, JSONObject jsonObject) throws Exception {
		//单个房源列表页采集
		List<ElementRule> topElementRules = elementRuleDao.findByUuidAndDepth(rule.getUuid(), depths.get(depths.size() - 2));
		jsonObject = HtmlAnalysisUtils.mainAnalysisRule(listTopBlock, ElementRuleDaoConvert.convertElementRuleToResolveElements(topElementRules), jsonObject, null);
        return analyseDetail(rule, depths, jsonObject);


    }

    private JSONObject analyseDetail(CollectRule rule, List<Integer> depths, JSONObject jsonObject) {
        //单个房源详情采集
        List<ElementRule> detailElementRules = elementRuleDao.findByUuidAndDepth(rule.getUuid(), depths.get(depths.size() - 1));
        String url = jsonObject.getString(HtmlAnalysisConsts.TITLE_LINK);
        RequestResponseInfo requestResponseInfo = HttpClientUtils.getPagetext(url, rule.getDetailWebCode());
        Document detailElement = Jsoup.parse(requestResponseInfo.getResponseText());
        jsonObject = HtmlAnalysisUtils.mainAnalysisRule(detailElement, ElementRuleDaoConvert.convertElementRuleToResolveElements(detailElementRules), jsonObject, null);
        jsonObject.put(CollectRuleFieldEnum.REQUEST_DETAIL_URL.getValue(), requestResponseInfo.getRequestUrl());
        if (HtmlAnalysisConsts.COLLECT_TYPE_RENT.equals(rule.getCollectType())) {
            if (HtmlAnalysisConsts.SOURCE_58.equals(rule.getSource()) || HtmlAnalysisConsts.SOURCE_GJW.equals(rule.getSource())) {
                RecognitionPhoneNumberUtils.recoginatePhonenumber(jsonObject);
            }
        }
        return jsonObject;
    }


    @Override
	public void inputCityDataToDbByUuid(List<String> uuids) {
		collectRuleDao.inputCityDataToDbByUuid(uuids);
	}
}
